En este trabajo se replicarán gráficos útiles para visualizar y
resumir variables categóricas.
ANALISIS DESCRIPTIVO
Se utilizarán los datos de fútbol del paquete ggcleveland,
con datos sobre la distancia (dist) que recorre la pelota al ser pateada
según la longitud de pierna (longp) del jugador. Estos datos pueden
considerarse univariados, ya que son mediciones de una única variable
cuantitativa (la distancia). La longitud de pierna es una variable
categórica que clasifica a los jugadores en distintos grupos. El
objetivo es determinar si la distancia está relacionada con la longitud
de pierna. Se podría esperar que los jugadores de piernas más largas
tengan una contextura física mayor y por lo tanto posean mayor potencia
al patear.
Resumen y visualización de los datos:
summary(futbol)
## longp dist
## Length:300 Min. : 30.00
## Class :character 1st Qu.: 60.00
## Mode :character Median : 71.00
## Mean : 70.07
## 3rd Qu.: 81.00
## Max. :114.00
futbol
GRÁFICO DE BARRAS
tabla_frec <- count(futbol, longp, name = "Frecuencia")
tabla_frec
tabla_frec=mutate(tabla_frec,
porcentaje_etiqueta=str_c(as.character(round(tabla_frec$Frecuencia/sum(tabla_frec$Frecuencia)*100)),"%"),
porcentaje=tabla_frec$Frecuencia/sum(tabla_frec$Frecuencia)*100,
longp=factor(longp, levels=c("1.21 m y +",
"1.11 a 1.20 m",
"1.01 a 1.10 m",
"0.91 a 1.00 m",
"0.81 a 0.90 m",
"< 0.81 m"))
)
ggplot(data = tabla_frec) +
coord_flip()+
aes(x = longp, y = porcentaje, fill=porcentaje) +
geom_bar(stat = "identity") +
scale_fill_continuous(low = "lightblue", high = "blue") +
geom_label(
aes(label = porcentaje_etiqueta),
vjust = 0.5, size = 5,hjust=1,
color = "black",
position = "identity"
) +
scale_y_continuous(breaks = seq(0, 60, 10)) +
labs(x = "Longitud de pierna", y = "Porcentaje")+
theme(legend.position = "none")

Este gráfico tiene orientación horizontal, el color de cada barra
está asociado a su magnitud y el eje X representa los porcentajes de
cada categoría de longitud de pierna. Se observa que la categoría de
longitud de pierna más popular es “<0.81 m” con aproximadamente un
19%, seguida por “1.11 a 1.20 m” con aproximadamente un 17%.
MOSAICOS
Se toma la variable dist de los datos futbol y se convierte en un
factor con dos niveles: “distancia recorrida menor a 50 mts.” y
“distancia mayor o igual a 50 mts.”.
A partir de ello se realizan gráficos de mosaico, con test de
independencia incluido, para comparar grupos de longitudes de pierna
sucesivos (comparaciones de a 2).
1er vs 2do grupo
futbol2=filter(futbol,(longp=="< 0.81 m")|(longp=="0.81 a 0.90 m"))
futbol2=mutate(futbol2,
dist2=ifelse(futbol2$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist2, data = futbol2, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “< 0.81 m”
patean una distancia entre [50;115) en menor proporción que los que
tienen una longitud de pierna de “0.81 a 0.90 m” pero es al revés para
una distancia entre “[30;50)”
\(H_0)\) La longitud de pierna y la
distancia son independientes
\(H_1)\) La longitud de pierna y la
distancia no son independientes
En base a la evidencia muestral y con un nivel de significación del
5% se concluye que se rechaza la hipótesis nula de independencia entre
la longitud de pierna y la distancia ya que se observa un valor de
probabilidad asociado menor a 0.05. Estas variables se distribuyen de
diferente forma para los distintos niveles de la otra.
2er vs 3er grupo
futbol3=filter(futbol,(longp=="0.81 a 0.90 m")|(longp=="0.91 a 1.00 m"))
futbol3=mutate(futbol3,
dist3=ifelse(futbol3$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist3, data = futbol3, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “0.81 a 0.90
m” patean una distancia entre [50;115) en menor proporción que los que
tienen una longitud de pierna de “0.91 a 1.00 m” pero es al revés para
una distancia entre “[30;50)”.
\(H_0)\) La longitud de pierna y la
distancia son independientes
\(H_1)\) La longitud de pierna y la
distancia no son independientes
En base a la evidencia muestral y con un nivel de significación del
5% se concluye que se rechaza la hipótesis nula de independencia entre
la longitud de pierna y la distancia ya que se observa un valor de
probabilidad asociado menor a 0.05. Estas variables se distribuyen de
diferente forma para los distintos niveles de la otra.
3er vs 4to grupo
futbol4=filter(futbol,(longp=="0.91 a 1.00 m")|(longp=="1.01 a 1.10 m"))
futbol4=mutate(futbol4,
dist4=ifelse(futbol4$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist4, data = futbol4, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “0.91 a 1.00
m” patean una distancia entre [50;115) en proporción muy similar que los
que tienen una longitud de pierna de “1.01 a 1.10 m” y se observa lo
mismo para una distancia entre “[30;50)”.
\(H_0)\) La longitud de pierna y la
distancia son independientes
\(H_1)\) La longitud de pierna y la
distancia no son independientes
En base a la evidencia muestral y con un nivel de significación del
5% se concluye que no se rechaza la hipótesis nula de independencia
entre la longitud de pierna y la distancia ya que se observa un valor de
probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el
cumplimiento de los supuestos del test de independencia.
4to vs 5to grupo
futbol5=filter(futbol,(longp=="1.01 a 1.10 m")|(longp=="1.11 a 1.20 m"))
futbol5=mutate(futbol5,
dist5=ifelse(futbol5$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist5, data = futbol5, direction = "v", shade = TRUE)

Se observa que los jugadores con una longitud de pierna “1.01 a 1.10
m” patean una distancia entre [50;115) proporción similar a los que
tienen una longitud de pierna de “1.11 a 1.20 m” pero parece ser
levemente mayor la cantidad de jugadores con longitud de pierna “1.01 a
1.10 m” que patean una distancia entre “[30;50)”.
\(H_0)\) La longitud de pierna y la
distancia son independientes
\(H_1)\) La longitud de pierna y la
distancia no son independientes
En base a la evidencia muestral y con un nivel de significación del
5% se concluye que no se rechaza la hipótesis nula de independencia
entre la longitud de pierna y la distancia ya que se observa un valor de
probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el
cumplimiento de los supuestos del test de independencia.
5to vs 6to grupo
futbol6=filter(futbol,(longp=="1.11 a 1.20 m")|(longp=="1.21 m y +"))
futbol6=mutate(futbol6,
dist6=ifelse(futbol6$dist<50,"[30;50)","[50;115)")
)
mosaic( ~ longp + dist6, data = futbol6, direction = "v", shade = TRUE)
## Warning in legend(residuals, gpfun, residuals_type): All residuals are zero.

Se observa que todos los jugadores con longitud de pierna “1.11 a
1.20 m” y “1.21 m y +” patean la pelota a una distancia entre 50 y 115
m.
\(H_0)\) La longitud de pierna y la
distancia son independientes
\(H_1)\) La longitud de pierna y la
distancia no son independientes
En base a la evidencia muestral y con un nivel de significación del
5% se concluye que no se rechaza la hipótesis nula de independencia
entre la longitud de pierna y la distancia ya que se observa un valor de
probabilidad asociado mayor a 0.05. Debe tenerse en cuenta el
cumplimiento de los supuestos del test de independencia.
ALLUVIAL
Para este gráfico se utilizan datos sobre toneladas producidas en
Argentina de varios tipos de cultivos (soja, trigo, cebada, etc.)
desagregados a nivel provincial y departamental para la campaña agrícola
2019/20.
A partir de estos se genera un gráfico alluvial para comparar las
producciones de sorgo y girasol en las provincias de Santa Fe, Córdoba y
La Pampa.
Resumen y visualización de los datos:
load("C:/Users/Temp/Documents/1 Facultad/Tercero/TAE/TP 4/cultivos.RData")
summary(cultivos)
## prov depto cultivo prod
## Length:1951 Length:1951 Length:1951 Min. : 25
## Class :character Class :character Class :character 1st Qu.: 1500
## Mode :character Mode :character Mode :character Median : 8100
## Mean : 73026
## 3rd Qu.: 50075
## Max. :2915400
cultivos
cultivos2 <- cultivos %>%
filter(prov=="CORDOBA"|prov=="LA PAMPA"|prov=="SANTA FE") %>%
filter(cultivo=="Girasol"|cultivo=="Sorgo") %>%
group_by(prov,cultivo) %>%
summarise(prod = sum(prod))
cultivos2=mutate(cultivos2,"Tn. (100.000)"=prod/100000)
cultivos2 %>%
#as.data.frame() %>%
ggplot() +
aes(axis1 = prov, axis2 = cultivo, fill = `Tn. (100.000)`, y = prod) +
geom_alluvium() + #flujos
geom_stratum( #columnas
fill = "black",
color = "lightgrey",
width = 0.1
) +
geom_label( #etiquetas
stat = "stratum",
aes(label = after_stat(stratum)),
fill = "white",
size = 2
) +
scale_x_discrete(limits = c("Provincia", "Cultivo"), expand = c(0, 0)) +
scale_y_continuous(name = "Produccion en (100.000 Tn.)", breaks = seq(0, 1500000, 500000), labels =seq(0, 15, 5) )+
scale_fill_continuous(low = "yellow", high = "red")

A partir de este gráfico se observa que Santa Fe es la provincia que
tiene mayor producción de Sorgo y de Girasol, y que esta es similar para
ambos cultivos. Mientras que Córdoba y La Pampa producen cantidades
diferentes de Sorgo y Girasol (Córdoba produce mayor cantidad de Sorgo y
La Pampa produce mayor cantidad de Girasol).
TREEMAPS
Para este gráfico se utiliza el conjunto de datos Titanic del paquete
de R Base datasets que contiene el porcentaje de pasajeros/as que
sobrevivieron a la tragedia del barco, desagregados según edad, género y
clase en la que viajaban.
Resumen y visualización de los datos:
A partir de estos datos se replica un treemap dinámico que muestra
los porcentajes de supervivencia según la clase en la que viajaba cada
pasajero:
titanic=as.data.frame(Titanic)
titanic=mutate(titanic,Survived=ifelse(Survived=="No","No Sobrevivió","Sobrevivió"))
titanic2 <- titanic %>%
group_by(Class, Survived) %>%
summarise(Freq = sum(Freq)) %>%
ungroup()
## `summarise()` has grouped output by 'Class'. You can override using the
## `.groups` argument.
titanic_tot <- titanic2 %>%
group_by(Class) %>%
summarise(Freq = sum(Freq))%>%
ungroup() %>%
rename(Survived = Class) %>%
mutate(Class = "Total Titanic") %>%
bind_rows(titanic2)%>%
mutate(etiq = ifelse(Class != "Total Titanic",
paste0(Survived, "_", Class),
as.character(Survived)))
plot_ly(
type = "treemap",
labels = titanic_tot$etiq, #variable de menor jerarquía (etiqueta única)
parents = titanic_tot$Class, #variable de mayor jerarquía
values = titanic_tot$Freq, #tamaño de cada rectángulo
hoverinfo = "label+value+percent parent+percent root",
textinfo = "label+value+percent parent+percent root"
)%>%
add_trace(branchvalues = "total", name = "")
A partir de este gráfico se observa que de la tripulación no
sobrevivieron 673 pasajeros que representan el 31% del total de los
pasajeros del Titanic y el 76% de la tripulación. Mientras que,
sobrevivieron 212 pasajeros de la tripulación. De los pasajeros que
viajaron en primera clase sobrevivió el 62% (203 pasajeros), que
representa el 9% del total de pasajeros. Siendo mayor el porcentaje de
pasajeros que sobrevivieron.
Para la segunda y tercera clase, fue mayor el porcentaje de pasajeros
que no sobrevivieron, al igual que para la tripulación.
MAPAS
La georreferencia es una disciplina ligada al análisis de datos
recolectados a nivel geográfico. Esta característica implica que la
información que poseemos puede visualizarse de manera más eficiente
desde una perspectiva espacial, es decir, representando los datos en
mapas y no mediante gráficos, tablas u otros instrumentos. En esta parte
del trabajo se realizarán esta clase de mapas.
Las librerías a utilizar son:
#Mapas
library(sf)
library(tmap)
library(leaflet)
library(spData)
#Varios
library(dplyr)
library(tidyr)
library(readxl)
library(ggplot2)
library(stringr)
Para realizar estos gráficos se utiliza el conjunto de datos world
del paquete spData. Cada una de las 177 filas de esta base corresponde a
un país diferente, para los cuales se registran diversas variables:
nombre, continente, superficie, población, etc.
Resumen y visualización de los datos:
summary(world)
## iso_a2 name_long continent region_un
## Length:177 Length:177 Length:177 Length:177
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## subregion type area_km2 pop
## Length:177 Length:177 Min. : 2417 Min. :5.630e+04
## Class :character Class :character 1st Qu.: 46185 1st Qu.:3.755e+06
## Mode :character Mode :character Median : 185004 Median :1.040e+07
## Mean : 832558 Mean :4.282e+07
## 3rd Qu.: 621860 3rd Qu.:3.075e+07
## Max. :17018507 Max. :1.364e+09
## NA's :10
## lifeExp gdpPercap geom
## Min. :50.62 Min. : 597.1 MULTIPOLYGON :177
## 1st Qu.:64.96 1st Qu.: 3752.4 epsg:4326 : 0
## Median :72.87 Median : 10734.1 +proj=long...: 0
## Mean :70.85 Mean : 17106.0
## 3rd Qu.:76.78 3rd Qu.: 24232.7
## Max. :83.59 Max. :120860.1
## NA's :10 NA's :17
world
Paquete SF
Usando funciones del paquete sf, se grafican los países de América
del Sur asignando colores de acuerdo a su esperanza de vida.
data(world)
sudamerica= world %>% filter(continent == "South America")
ggplot(data = sudamerica) +
aes(fill = lifeExp) +
ggtitle("Esperanza de Vida (en Años) por País - Datos 2014")+
geom_sf() +
scale_fill_gradient(low = "red", high = "green") +
theme_bw()

A partir de este mapa se observa que Chile es el país con mayor
esperanza de vida entre los países de América del Sur, seguido por
Uruguay y Argentina. Mientras que, Guayana y Bolivia son los países con
menor esperanza de vida.
Paquete TMAP
Se realiza un mapa usando funciones del paquete tmap, donde se
comparan los valores de PBI per cápita de los países africanos:
tmap_mode("plot")
## tmap mode set to plotting
africa= world %>% filter(continent == "Africa")
africa %>%
tm_shape() +
tm_fill(id = "name_long", col = "gdpPercap") +
tm_style("cobalt") +
tm_borders("black", lwd = 1) +
tm_minimap() +
tm_basemap("Stamen.TonerBackground")+
tm_text( "name_long", size=.6)

A partir de este mapa se observa que los países con mayor PBI per
cápita en África son Guinea Ecuatorial, Libia y Botswana. Mientras que
los de menor PBI per cápita son, entre otros; Nigeria, Sudán,
Madagascar, etc. Hay mayor proporción de países con PBI per cápita
bajo.
LS0tDQp0aXRsZTogIkFuYWxpc2lzIEV4cGxvcmF0aW9yaW8gZGUgRGF0b3MiDQphdXRob3I6ICJSb23DoW4gTGFuZGEiDQpkYXRlOiAiMjAyMi0xMS0yMyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGRmX3ByaW50OiBwYWdlZA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQpFbiBlc3RlIHRyYWJham8gc2UgcmVwbGljYXLDoW4gZ3LDoWZpY29zIMO6dGlsZXMgcGFyYSB2aXN1YWxpemFyIHkgcmVzdW1pciB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLg0KDQpMYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzIHNvbjoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KbGlicmFyeSh2Y2QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnYWxsdXZpYWwpDQpsaWJyYXJ5KGdnY2xldmVsYW5kKQ0KbGlicmFyeSh0cmVlbWFwaWZ5KQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkobGF0dGljZSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQpTZSBmaWphIHVuIHRlbWEgcGFyYSBsb3MgZ3LDoWZpY29zOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KYGBgDQoNCiMgQU5BTElTSVMgREVTQ1JJUFRJVk8NCg0KU2UgdXRpbGl6YXLDoW4gbG9zIGRhdG9zIGRlIGbDunRib2wgZGVsIHBhcXVldGUgKmdnY2xldmVsYW5kKiwgY29uIGRhdG9zIHNvYnJlIGxhIGRpc3RhbmNpYSAoZGlzdCkgcXVlIHJlY29ycmUgbGEgcGVsb3RhIGFsIHNlciBwYXRlYWRhIHNlZ8O6biBsYSBsb25naXR1ZCBkZSBwaWVybmEgKGxvbmdwKSBkZWwganVnYWRvci4NCkVzdG9zIGRhdG9zIHB1ZWRlbiBjb25zaWRlcmFyc2UgdW5pdmFyaWFkb3MsIHlhIHF1ZSBzb24gbWVkaWNpb25lcyBkZSB1bmEgw7puaWNhIHZhcmlhYmxlIGN1YW50aXRhdGl2YSAobGEgZGlzdGFuY2lhKS4gTGEgbG9uZ2l0dWQgZGUgcGllcm5hIGVzIHVuYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSBxdWUgY2xhc2lmaWNhIGEgbG9zIGp1Z2Fkb3JlcyBlbiBkaXN0aW50b3MgZ3J1cG9zLg0KRWwgb2JqZXRpdm8gZXMgZGV0ZXJtaW5hciBzaSBsYSBkaXN0YW5jaWEgZXN0w6EgcmVsYWNpb25hZGEgY29uIGxhIGxvbmdpdHVkIGRlIHBpZXJuYS4gU2UgcG9kcsOtYSBlc3BlcmFyIHF1ZSBsb3MganVnYWRvcmVzIGRlIHBpZXJuYXMgbcOhcyBsYXJnYXMgdGVuZ2FuIHVuYSBjb250ZXh0dXJhIGbDrXNpY2EgbWF5b3IgeSBwb3IgbG8gdGFudG8gcG9zZWFuIG1heW9yIHBvdGVuY2lhIGFsIHBhdGVhci4NCg0KUmVzdW1lbiB5IHZpc3VhbGl6YWNpw7NuIGRlIGxvcyBkYXRvczoNCmBgYHtyfQ0Kc3VtbWFyeShmdXRib2wpDQpmdXRib2wNCmBgYA0KDQoNCiMjIEdSw4FGSUNPIERFIEJBUlJBUw0KDQpgYGB7cn0NCnRhYmxhX2ZyZWMgPC0gY291bnQoZnV0Ym9sLCBsb25ncCwgbmFtZSA9ICJGcmVjdWVuY2lhIikNCnRhYmxhX2ZyZWMNCnRhYmxhX2ZyZWM9bXV0YXRlKHRhYmxhX2ZyZWMsIA0KICAgICAgICAgICAgICAgICAgcG9yY2VudGFqZV9ldGlxdWV0YT1zdHJfYyhhcy5jaGFyYWN0ZXIocm91bmQodGFibGFfZnJlYyRGcmVjdWVuY2lhL3N1bSh0YWJsYV9mcmVjJEZyZWN1ZW5jaWEpKjEwMCkpLCIlIiksDQogICAgICAgICAgICAgICAgICBwb3JjZW50YWplPXRhYmxhX2ZyZWMkRnJlY3VlbmNpYS9zdW0odGFibGFfZnJlYyRGcmVjdWVuY2lhKSoxMDAsDQogICAgICAgICAgICAgICAgICBsb25ncD1mYWN0b3IobG9uZ3AsIGxldmVscz1jKCIxLjIxIG0geSArIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMS4xMSBhIDEuMjAgbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEuMDEgYSAxLjEwIG0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjkxIGEgMS4wMCBtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC44MSBhIDAuOTAgbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjwgMC44MSBtIikpDQogICAgICAgICAgICAgICAgICApDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gdGFibGFfZnJlYykgKw0KICBjb29yZF9mbGlwKCkrDQogIGFlcyh4ID0gbG9uZ3AsIHkgPSBwb3JjZW50YWplLCBmaWxsPXBvcmNlbnRhamUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJsaWdodGJsdWUiLCBoaWdoID0gImJsdWUiKSArDQogIGdlb21fbGFiZWwoDQogICAgYWVzKGxhYmVsID0gcG9yY2VudGFqZV9ldGlxdWV0YSksIA0KICAgIHZqdXN0ID0gMC41LCBzaXplID0gNSxoanVzdD0xLA0KICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICBwb3NpdGlvbiA9ICJpZGVudGl0eSINCiAgKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjAsIDEwKSkgKw0KICBsYWJzKHggPSAiTG9uZ2l0dWQgZGUgcGllcm5hIiwgeSA9ICJQb3JjZW50YWplIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpFc3RlIGdyw6FmaWNvIHRpZW5lIG9yaWVudGFjacOzbiBob3Jpem9udGFsLCBlbCBjb2xvciBkZSBjYWRhIGJhcnJhIGVzdMOhIGFzb2NpYWRvIGEgc3UgbWFnbml0dWQgeSBlbCBlamUgWCByZXByZXNlbnRhIGxvcyBwb3JjZW50YWplcyBkZSBjYWRhIGNhdGVnb3LDrWEgZGUgbG9uZ2l0dWQgZGUgcGllcm5hLg0KU2Ugb2JzZXJ2YSBxdWUgbGEgY2F0ZWdvcsOtYSBkZSBsb25naXR1ZCBkZSBwaWVybmEgbcOhcyBwb3B1bGFyIGVzICI8MC44MSBtIiBjb24gYXByb3hpbWFkYW1lbnRlIHVuIDE5JSwgc2VndWlkYSBwb3IgIjEuMTEgYSAxLjIwIG0iIGNvbiBhcHJveGltYWRhbWVudGUgdW4gMTclLg0KDQojIyBNT1NBSUNPUw0KDQpTZSB0b21hIGxhIHZhcmlhYmxlIGRpc3QgZGUgbG9zIGRhdG9zIGZ1dGJvbCB5IHNlIGNvbnZpZXJ0ZSBlbiB1biBmYWN0b3IgY29uIGRvcyBuaXZlbGVzOiDigJxkaXN0YW5jaWEgcmVjb3JyaWRhIG1lbm9yIGEgNTAgbXRzLuKAnSB5IOKAnGRpc3RhbmNpYSBtYXlvciBvIGlndWFsIGEgNTAgbXRzLuKAnS4NCg0KQSBwYXJ0aXIgZGUgZWxsbyBzZSByZWFsaXphbiBncsOhZmljb3MgZGUgbW9zYWljbywgY29uIHRlc3QgZGUgaW5kZXBlbmRlbmNpYSBpbmNsdWlkbywgcGFyYSBjb21wYXJhciBncnVwb3MgZGUgbG9uZ2l0dWRlcyBkZSBwaWVybmEgc3VjZXNpdm9zIChjb21wYXJhY2lvbmVzIGRlIGEgMikuDQoNCiMjIyAxZXIgdnMgMmRvIGdydXBvDQoNCmBgYHtyfQ0KZnV0Ym9sMj1maWx0ZXIoZnV0Ym9sLChsb25ncD09IjwgMC44MSBtIil8KGxvbmdwPT0iMC44MSBhIDAuOTAgbSIpKQ0KZnV0Ym9sMj1tdXRhdGUoZnV0Ym9sMiwNCiAgICAgICAgICAgICAgIGRpc3QyPWlmZWxzZShmdXRib2wyJGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQogICAgICAgICAgICAgICApDQpgYGANCg0KDQpgYGB7cn0NCm1vc2FpYyggfiBsb25ncCArIGRpc3QyLCBkYXRhID0gZnV0Ym9sMiwgZGlyZWN0aW9uID0gInYiLCBzaGFkZSA9IFRSVUUpDQpgYGANCg0KDQpTZSBvYnNlcnZhIHF1ZSBsb3MganVnYWRvcmVzIGNvbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hICI8IDAuODEgbSIgcGF0ZWFuIHVuYSBkaXN0YW5jaWEgZW50cmUgWzUwOzExNSkgZW4gbWVub3IgcHJvcG9yY2nDs24gcXVlIGxvcyBxdWUgdGllbmVuIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgZGUgIjAuODEgYSAwLjkwIG0iIHBlcm8gZXMgYWwgcmV2w6lzIHBhcmEgdW5hIGRpc3RhbmNpYSBlbnRyZSAiWzMwOzUwKSINCg0KJEhfMCkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBzb24gaW5kZXBlbmRpZW50ZXMNCg0KJEhfMSkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBubyBzb24gaW5kZXBlbmRpZW50ZXMNCg0KRW4gYmFzZSBhIGxhIGV2aWRlbmNpYSBtdWVzdHJhbCB5IGNvbiB1biBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiBkZWwgNSUgc2UgY29uY2x1eWUgcXVlIHNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIGluZGVwZW5kZW5jaWEgZW50cmUgbGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHlhIHF1ZSBzZSBvYnNlcnZhIHVuIHZhbG9yIGRlIHByb2JhYmlsaWRhZCBhc29jaWFkbyBtZW5vciBhIDAuMDUuIEVzdGFzIHZhcmlhYmxlcyBzZSBkaXN0cmlidXllbiBkZSBkaWZlcmVudGUgZm9ybWEgcGFyYSBsb3MgZGlzdGludG9zIG5pdmVsZXMgZGUgbGEgb3RyYS4NCg0KDQojIyMgMmVyIHZzIDNlciBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDM9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIwLjgxIGEgMC45MCBtIil8KGxvbmdwPT0iMC45MSBhIDEuMDAgbSIpKQ0KZnV0Ym9sMz1tdXRhdGUoZnV0Ym9sMywNCiAgICAgICAgICAgICAgIGRpc3QzPWlmZWxzZShmdXRib2wzJGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0MywgZGF0YSA9IGZ1dGJvbDMsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjAuODEgYSAwLjkwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIGVuIG1lbm9yIHByb3BvcmNpw7NuIHF1ZSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIwLjkxIGEgMS4wMCBtIiBwZXJvIGVzIGFsIHJldsOpcyBwYXJhIHVuYSBkaXN0YW5jaWEgZW50cmUgIlszMDs1MCkiLg0KDQokSF8wKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHNvbiBpbmRlcGVuZGllbnRlcw0KDQokSF8xKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIG5vIHNvbiBpbmRlcGVuZGllbnRlcw0KDQpFbiBiYXNlIGEgbGEgZXZpZGVuY2lhIG11ZXN0cmFsIHkgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuIGRlbCA1JSBzZSBjb25jbHV5ZSBxdWUgc2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgaW5kZXBlbmRlbmNpYSBlbnRyZSBsYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgeWEgcXVlIHNlIG9ic2VydmEgdW4gdmFsb3IgZGUgcHJvYmFiaWxpZGFkIGFzb2NpYWRvIG1lbm9yIGEgMC4wNS4gRXN0YXMgdmFyaWFibGVzIHNlIGRpc3RyaWJ1eWVuIGRlIGRpZmVyZW50ZSBmb3JtYSBwYXJhIGxvcyBkaXN0aW50b3Mgbml2ZWxlcyBkZSBsYSBvdHJhLg0KDQojIyMgM2VyIHZzIDR0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDQ9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIwLjkxIGEgMS4wMCBtIil8KGxvbmdwPT0iMS4wMSBhIDEuMTAgbSIpKQ0KZnV0Ym9sND1tdXRhdGUoZnV0Ym9sNCwNCiAgICAgICAgICAgICAgIGRpc3Q0PWlmZWxzZShmdXRib2w0JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NCwgZGF0YSA9IGZ1dGJvbDQsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjAuOTEgYSAxLjAwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIGVuIHByb3BvcmNpw7NuIG11eSBzaW1pbGFyIHF1ZSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIxLjAxIGEgMS4xMCBtIiB5IHNlIG9ic2VydmEgbG8gbWlzbW8gcGFyYSB1bmEgZGlzdGFuY2lhIGVudHJlICJbMzA7NTApIi4NCg0KJEhfMCkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBzb24gaW5kZXBlbmRpZW50ZXMNCg0KJEhfMSkkIExhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSBubyBzb24gaW5kZXBlbmRpZW50ZXMNCg0KRW4gYmFzZSBhIGxhIGV2aWRlbmNpYSBtdWVzdHJhbCB5IGNvbiB1biBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiBkZWwgNSUgc2UgY29uY2x1eWUgcXVlIG5vIHNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhIGRlIGluZGVwZW5kZW5jaWEgZW50cmUgbGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHlhIHF1ZSBzZSBvYnNlcnZhIHVuIHZhbG9yIGRlIHByb2JhYmlsaWRhZCBhc29jaWFkbyBtYXlvciBhIDAuMDUuIERlYmUgdGVuZXJzZSBlbiBjdWVudGEgZWwgY3VtcGxpbWllbnRvIGRlIGxvcyBzdXB1ZXN0b3MgZGVsIHRlc3QgZGUgaW5kZXBlbmRlbmNpYS4NCg0KDQojIyMgNHRvIHZzIDV0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDU9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIxLjAxIGEgMS4xMCBtIil8KGxvbmdwPT0iMS4xMSBhIDEuMjAgbSIpKQ0KZnV0Ym9sNT1tdXRhdGUoZnV0Ym9sNSwNCiAgICAgICAgICAgICAgIGRpc3Q1PWlmZWxzZShmdXRib2w1JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NSwgZGF0YSA9IGZ1dGJvbDUsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIGxvcyBqdWdhZG9yZXMgY29uIHVuYSBsb25naXR1ZCBkZSBwaWVybmEgIjEuMDEgYSAxLjEwIG0iIHBhdGVhbiB1bmEgZGlzdGFuY2lhIGVudHJlIFs1MDsxMTUpIHByb3BvcmNpw7NuIHNpbWlsYXIgYSBsb3MgcXVlIHRpZW5lbiB1bmEgbG9uZ2l0dWQgZGUgcGllcm5hIGRlICIxLjExIGEgMS4yMCBtIiBwZXJvIHBhcmVjZSBzZXIgbGV2ZW1lbnRlIG1heW9yIGxhIGNhbnRpZGFkIGRlIGp1Z2Fkb3JlcyBjb24gbG9uZ2l0dWQgZGUgcGllcm5hICIxLjAxIGEgMS4xMCBtIiBxdWUgcGF0ZWFuIHVuYSBkaXN0YW5jaWEgZW50cmUgIlszMDs1MCkiLg0KDQokSF8wKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIHNvbiBpbmRlcGVuZGllbnRlcw0KDQokSF8xKSQgTGEgbG9uZ2l0dWQgZGUgcGllcm5hIHkgbGEgZGlzdGFuY2lhIG5vIHNvbiBpbmRlcGVuZGllbnRlcw0KDQpFbiBiYXNlIGEgbGEgZXZpZGVuY2lhIG11ZXN0cmFsIHkgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuIGRlbCA1JSBzZSBjb25jbHV5ZSBxdWUgbm8gc2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgaW5kZXBlbmRlbmNpYSBlbnRyZSBsYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgeWEgcXVlIHNlIG9ic2VydmEgdW4gdmFsb3IgZGUgcHJvYmFiaWxpZGFkIGFzb2NpYWRvIG1heW9yIGEgMC4wNS4gRGViZSB0ZW5lcnNlIGVuIGN1ZW50YSBlbCBjdW1wbGltaWVudG8gZGUgbG9zIHN1cHVlc3RvcyBkZWwgdGVzdCBkZSBpbmRlcGVuZGVuY2lhLg0KDQojIyMgNXRvIHZzIDZ0byBncnVwbw0KDQpgYGB7cn0NCmZ1dGJvbDY9ZmlsdGVyKGZ1dGJvbCwobG9uZ3A9PSIxLjExIGEgMS4yMCBtIil8KGxvbmdwPT0iMS4yMSBtIHkgKyIpKQ0KZnV0Ym9sNj1tdXRhdGUoZnV0Ym9sNiwNCiAgICAgICAgICAgICAgIGRpc3Q2PWlmZWxzZShmdXRib2w2JGRpc3Q8NTAsIlszMDs1MCkiLCJbNTA7MTE1KSIpDQopDQpgYGANCg0KYGBge3J9DQptb3NhaWMoIH4gbG9uZ3AgKyBkaXN0NiwgZGF0YSA9IGZ1dGJvbDYsIGRpcmVjdGlvbiA9ICJ2Iiwgc2hhZGUgPSBUUlVFKQ0KYGBgDQoNClNlIG9ic2VydmEgcXVlIHRvZG9zIGxvcyBqdWdhZG9yZXMgY29uIGxvbmdpdHVkIGRlIHBpZXJuYSAiMS4xMSBhIDEuMjAgbSIgeSAiMS4yMSBtIHkgKyIgcGF0ZWFuIGxhIHBlbG90YSBhIHVuYSBkaXN0YW5jaWEgZW50cmUgNTAgeSAxMTUgbS4gDQoNCiRIXzApJCBMYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgc29uIGluZGVwZW5kaWVudGVzDQoNCiRIXzEpJCBMYSBsb25naXR1ZCBkZSBwaWVybmEgeSBsYSBkaXN0YW5jaWEgbm8gc29uIGluZGVwZW5kaWVudGVzDQoNCkVuIGJhc2UgYSBsYSBldmlkZW5jaWEgbXVlc3RyYWwgeSBjb24gdW4gbml2ZWwgZGUgc2lnbmlmaWNhY2nDs24gZGVsIDUlIHNlIGNvbmNsdXllIHF1ZSBubyBzZSByZWNoYXphIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSBpbmRlcGVuZGVuY2lhIGVudHJlIGxhIGxvbmdpdHVkIGRlIHBpZXJuYSB5IGxhIGRpc3RhbmNpYSB5YSBxdWUgc2Ugb2JzZXJ2YSB1biB2YWxvciBkZSBwcm9iYWJpbGlkYWQgYXNvY2lhZG8gbWF5b3IgYSAwLjA1LiBEZWJlIHRlbmVyc2UgZW4gY3VlbnRhIGVsIGN1bXBsaW1pZW50byBkZSBsb3Mgc3VwdWVzdG9zIGRlbCB0ZXN0IGRlIGluZGVwZW5kZW5jaWEuDQoNCg0KIyMgQUxMVVZJQUwNCg0KUGFyYSBlc3RlIGdyw6FmaWNvIHNlIHV0aWxpemFuIGRhdG9zIHNvYnJlIHRvbmVsYWRhcyBwcm9kdWNpZGFzIGVuIEFyZ2VudGluYSBkZSB2YXJpb3MgdGlwb3MgZGUgY3VsdGl2b3MgKHNvamEsIHRyaWdvLCBjZWJhZGEsIGV0Yy4pIGRlc2FncmVnYWRvcyBhIG5pdmVsIHByb3ZpbmNpYWwgeSBkZXBhcnRhbWVudGFsIHBhcmEgbGEgY2FtcGHDsWEgYWdyw61jb2xhIDIwMTkvMjAuDQoNCkEgcGFydGlyIGRlIGVzdG9zIHNlIGdlbmVyYSB1biBncsOhZmljbyBhbGx1dmlhbCBwYXJhIGNvbXBhcmFyIGxhcyBwcm9kdWNjaW9uZXMgZGUgc29yZ28geSBnaXJhc29sIGVuIGxhcyBwcm92aW5jaWFzIGRlIFNhbnRhIEZlLCBDw7NyZG9iYSB5IExhIFBhbXBhLg0KDQpSZXN1bWVuIHkgdmlzdWFsaXphY2nDs24gZGUgbG9zIGRhdG9zOg0KDQpgYGB7cn0NCmxvYWQoIkM6L1VzZXJzL1RlbXAvRG9jdW1lbnRzLzEgRmFjdWx0YWQvVGVyY2Vyby9UQUUvVFAgNC9jdWx0aXZvcy5SRGF0YSIpDQpzdW1tYXJ5KGN1bHRpdm9zKQ0KY3VsdGl2b3MNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQpjdWx0aXZvczIgPC0gY3VsdGl2b3MgJT4lIA0KICAgICBmaWx0ZXIocHJvdj09IkNPUkRPQkEifHByb3Y9PSJMQSBQQU1QQSJ8cHJvdj09IlNBTlRBIEZFIikgJT4lDQogICAgIGZpbHRlcihjdWx0aXZvPT0iR2lyYXNvbCJ8Y3VsdGl2bz09IlNvcmdvIikgJT4lDQogICAgIGdyb3VwX2J5KHByb3YsY3VsdGl2bykgJT4lIA0KICAgICBzdW1tYXJpc2UocHJvZCA9IHN1bShwcm9kKSkNCmN1bHRpdm9zMj1tdXRhdGUoY3VsdGl2b3MyLCJUbi4gKDEwMC4wMDApIj1wcm9kLzEwMDAwMCkNCmBgYA0KDQoNCmBgYHtyfQ0KY3VsdGl2b3MyICU+JSANCiAgI2FzLmRhdGEuZnJhbWUoKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGFlcyhheGlzMSA9IHByb3YsIGF4aXMyID0gY3VsdGl2bywgZmlsbCA9IGBUbi4gKDEwMC4wMDApYCwgeSA9IHByb2QpICsNCiAgZ2VvbV9hbGx1dml1bSgpICsgI2ZsdWpvcw0KICBnZW9tX3N0cmF0dW0oICNjb2x1bW5hcw0KICAgIGZpbGwgPSAiYmxhY2siLCANCiAgICBjb2xvciA9ICJsaWdodGdyZXkiLA0KICAgIHdpZHRoID0gMC4xDQogICkgKyANCiAgZ2VvbV9sYWJlbCggI2V0aXF1ZXRhcw0KICAgIHN0YXQgPSAic3RyYXR1bSIsIA0KICAgIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpLA0KICAgIGZpbGwgPSAid2hpdGUiLA0KICAgIHNpemUgPSAyDQogICkgKyANCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJQcm92aW5jaWEiLCAiQ3VsdGl2byIpLCBleHBhbmQgPSBjKDAsIDApKSArDQogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlByb2R1Y2Npb24gZW4gKDEwMC4wMDAgVG4uKSIsIGJyZWFrcyA9IHNlcSgwLCAxNTAwMDAwLCA1MDAwMDApLCBsYWJlbHMgPXNlcSgwLCAxNSwgNSkgKSsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIpDQoNCmBgYA0KDQoNCkEgcGFydGlyIGRlIGVzdGUgZ3LDoWZpY28gc2Ugb2JzZXJ2YSBxdWUgU2FudGEgRmUgZXMgbGEgcHJvdmluY2lhIHF1ZSB0aWVuZSBtYXlvciBwcm9kdWNjacOzbiBkZSBTb3JnbyB5IGRlIEdpcmFzb2wsIHkgcXVlIGVzdGEgZXMgc2ltaWxhciBwYXJhIGFtYm9zIGN1bHRpdm9zLiBNaWVudHJhcyBxdWUgQ8OzcmRvYmEgeSBMYSBQYW1wYSBwcm9kdWNlbiBjYW50aWRhZGVzIGRpZmVyZW50ZXMgZGUgU29yZ28geSBHaXJhc29sIChDw7NyZG9iYSBwcm9kdWNlIG1heW9yIGNhbnRpZGFkIGRlIFNvcmdvIHkgTGEgUGFtcGEgcHJvZHVjZSBtYXlvciBjYW50aWRhZCBkZSBHaXJhc29sKS4NCg0KIyMgVFJFRU1BUFMNCg0KUGFyYSBlc3RlIGdyw6FmaWNvIHNlIHV0aWxpemEgZWwgY29uanVudG8gZGUgZGF0b3MgVGl0YW5pYyBkZWwgcGFxdWV0ZSBkZSBSIEJhc2UgZGF0YXNldHMgcXVlIGNvbnRpZW5lIGVsIHBvcmNlbnRhamUgZGUgcGFzYWplcm9zL2FzIHF1ZSBzb2JyZXZpdmllcm9uIGEgbGEgdHJhZ2VkaWEgZGVsIGJhcmNvLCBkZXNhZ3JlZ2Fkb3Mgc2Vnw7puIGVkYWQsIGfDqW5lcm8geSBjbGFzZSBlbiBsYSBxdWUgdmlhamFiYW4uDQoNClJlc3VtZW4geSB2aXN1YWxpemFjacOzbiBkZSBsb3MgZGF0b3M6DQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpzdW1tYXJ5KFRpdGFuaWMpDQpUaXRhbmljDQpgYGANCg0KQSBwYXJ0aXIgZGUgZXN0b3MgZGF0b3Mgc2UgcmVwbGljYSB1biB0cmVlbWFwIGRpbsOhbWljbyBxdWUgbXVlc3RyYSBsb3MgcG9yY2VudGFqZXMgZGUgc3VwZXJ2aXZlbmNpYSBzZWfDum4gbGEgY2xhc2UgZW4gbGEgcXVlIHZpYWphYmEgY2FkYSBwYXNhamVybzoNCg0KYGBge3J9DQp0aXRhbmljPWFzLmRhdGEuZnJhbWUoVGl0YW5pYykNCnRpdGFuaWM9bXV0YXRlKHRpdGFuaWMsU3Vydml2ZWQ9aWZlbHNlKFN1cnZpdmVkPT0iTm8iLCJObyBTb2JyZXZpdmnDsyIsIlNvYnJldml2acOzIikpDQoNCnRpdGFuaWMyIDwtIHRpdGFuaWMgJT4lIA0KICBncm91cF9ieShDbGFzcywgU3Vydml2ZWQpICU+JSANCiAgc3VtbWFyaXNlKEZyZXEgPSBzdW0oRnJlcSkpICU+JSANCiAgdW5ncm91cCgpDQoNCnRpdGFuaWNfdG90IDwtIHRpdGFuaWMyICU+JSANCiAgZ3JvdXBfYnkoQ2xhc3MpICU+JSANCiAgc3VtbWFyaXNlKEZyZXEgPSBzdW0oRnJlcSkpJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIHJlbmFtZShTdXJ2aXZlZCA9IENsYXNzKSAlPiUgDQogIG11dGF0ZShDbGFzcyA9ICJUb3RhbCBUaXRhbmljIikgJT4lDQogIGJpbmRfcm93cyh0aXRhbmljMiklPiUNCiAgbXV0YXRlKGV0aXEgPSBpZmVsc2UoQ2xhc3MgIT0gIlRvdGFsIFRpdGFuaWMiLA0KICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoU3Vydml2ZWQsICJfIiwgQ2xhc3MpLA0KICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoU3Vydml2ZWQpKSkNCmBgYA0KDQpgYGB7cn0NCnBsb3RfbHkoDQogIHR5cGUgPSAidHJlZW1hcCIsDQogIGxhYmVscyA9IHRpdGFuaWNfdG90JGV0aXEsICN2YXJpYWJsZSBkZSBtZW5vciBqZXJhcnF1w61hIChldGlxdWV0YSDDum5pY2EpDQogIHBhcmVudHMgPSB0aXRhbmljX3RvdCRDbGFzcywgI3ZhcmlhYmxlIGRlIG1heW9yIGplcmFycXXDrWENCiAgdmFsdWVzID0gdGl0YW5pY190b3QkRnJlcSwgI3RhbWHDsW8gZGUgY2FkYSByZWN0w6FuZ3Vsbw0KICBob3ZlcmluZm8gPSAibGFiZWwrdmFsdWUrcGVyY2VudCBwYXJlbnQrcGVyY2VudCByb290IiwNCiAgdGV4dGluZm8gPSAibGFiZWwrdmFsdWUrcGVyY2VudCBwYXJlbnQrcGVyY2VudCByb290Ig0KKSU+JQ0KICBhZGRfdHJhY2UoYnJhbmNodmFsdWVzID0gInRvdGFsIiwgbmFtZSA9ICIiKQ0KDQpgYGANCg0KDQpBIHBhcnRpciBkZSBlc3RlIGdyw6FmaWNvIHNlIG9ic2VydmEgcXVlIGRlIGxhIHRyaXB1bGFjacOzbiBubyBzb2JyZXZpdmllcm9uIDY3MyBwYXNhamVyb3MgcXVlIHJlcHJlc2VudGFuIGVsIDMxJSBkZWwgdG90YWwgZGUgbG9zIHBhc2FqZXJvcyBkZWwgVGl0YW5pYyB5IGVsIDc2JSBkZSBsYSB0cmlwdWxhY2nDs24uIE1pZW50cmFzIHF1ZSwgc29icmV2aXZpZXJvbiAyMTIgcGFzYWplcm9zIGRlIGxhIHRyaXB1bGFjacOzbi4NCkRlIGxvcyBwYXNhamVyb3MgcXVlIHZpYWphcm9uIGVuIHByaW1lcmEgY2xhc2Ugc29icmV2aXZpw7MgZWwgNjIlICgyMDMgcGFzYWplcm9zKSwgcXVlIHJlcHJlc2VudGEgZWwgOSUgZGVsIHRvdGFsIGRlIHBhc2FqZXJvcy4gU2llbmRvIG1heW9yIGVsIHBvcmNlbnRhamUgZGUgcGFzYWplcm9zIHF1ZSBzb2JyZXZpdmllcm9uLiAgDQpQYXJhIGxhIHNlZ3VuZGEgeSB0ZXJjZXJhIGNsYXNlLCBmdWUgbWF5b3IgZWwgcG9yY2VudGFqZSBkZSBwYXNhamVyb3MgcXVlIG5vIHNvYnJldml2aWVyb24sIGFsIGlndWFsIHF1ZSBwYXJhIGxhIHRyaXB1bGFjacOzbi4NCg0KIyBNQVBBUw0KDQpMYSBnZW9ycmVmZXJlbmNpYSBlcyB1bmEgZGlzY2lwbGluYSBsaWdhZGEgYWwgYW7DoWxpc2lzIGRlIGRhdG9zIHJlY29sZWN0YWRvcyBhIG5pdmVsIGdlb2dyw6FmaWNvLiBFc3RhIGNhcmFjdGVyw61zdGljYSBpbXBsaWNhIHF1ZSBsYSBpbmZvcm1hY2nDs24gcXVlIHBvc2VlbW9zIHB1ZWRlIHZpc3VhbGl6YXJzZSBkZSBtYW5lcmEgbcOhcyBlZmljaWVudGUgZGVzZGUgdW5hIHBlcnNwZWN0aXZhIGVzcGFjaWFsLCBlcyBkZWNpciwgcmVwcmVzZW50YW5kbyBsb3MgZGF0b3MgZW4gbWFwYXMgeSBubyBtZWRpYW50ZSBncsOhZmljb3MsIHRhYmxhcyB1IG90cm9zIGluc3RydW1lbnRvcy4NCkVuIGVzdGEgcGFydGUgZGVsIHRyYWJham8gc2UgcmVhbGl6YXLDoW4gZXN0YSBjbGFzZSBkZSBtYXBhcy4NCg0KTGFzIGxpYnJlcsOtYXMgYSB1dGlsaXphciBzb246DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KI01hcGFzDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzcERhdGEpDQojVmFyaW9zDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzdHJpbmdyKQ0KYGBgDQoNClBhcmEgcmVhbGl6YXIgZXN0b3MgZ3LDoWZpY29zIHNlIHV0aWxpemEgZWwgY29uanVudG8gZGUgZGF0b3Mgd29ybGQgZGVsIHBhcXVldGUgc3BEYXRhLiBDYWRhIHVuYSBkZSBsYXMgMTc3IGZpbGFzIGRlIGVzdGEgYmFzZSBjb3JyZXNwb25kZSBhIHVuIHBhw61zIGRpZmVyZW50ZSwgcGFyYSBsb3MgY3VhbGVzIHNlIHJlZ2lzdHJhbiBkaXZlcnNhcyB2YXJpYWJsZXM6IG5vbWJyZSwgY29udGluZW50ZSwgc3VwZXJmaWNpZSwgcG9ibGFjacOzbiwgZXRjLg0KDQpSZXN1bWVuIHkgdmlzdWFsaXphY2nDs24gZGUgbG9zIGRhdG9zOg0KDQpgYGB7cn0NCnN1bW1hcnkod29ybGQpDQp3b3JsZA0KYGBgDQoNCiMjIFBhcXVldGUgU0YNCg0KVXNhbmRvIGZ1bmNpb25lcyBkZWwgcGFxdWV0ZSBzZiwgc2UgZ3JhZmljYW4gbG9zIHBhw61zZXMgZGUgQW3DqXJpY2EgZGVsIFN1ciBhc2lnbmFuZG8gY29sb3JlcyBkZSBhY3VlcmRvIGEgc3UgZXNwZXJhbnphIGRlIHZpZGEuIA0KDQpgYGB7cn0NCmRhdGEod29ybGQpDQpzdWRhbWVyaWNhPSB3b3JsZCAlPiUgZmlsdGVyKGNvbnRpbmVudCA9PSAiU291dGggQW1lcmljYSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHN1ZGFtZXJpY2EpICsNCiAgYWVzKGZpbGwgPSBsaWZlRXhwKSArDQogIGdndGl0bGUoIkVzcGVyYW56YSBkZSBWaWRhIChlbiBBw7FvcykgcG9yIFBhw61zIC0gRGF0b3MgMjAxNCIpKw0KICBnZW9tX3NmKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiLCBoaWdoID0gImdyZWVuIikgKw0KICB0aGVtZV9idygpDQpgYGANCg0KQSBwYXJ0aXIgZGUgZXN0ZSBtYXBhIHNlIG9ic2VydmEgcXVlIENoaWxlIGVzIGVsIHBhw61zIGNvbiBtYXlvciBlc3BlcmFuemEgZGUgdmlkYSBlbnRyZSBsb3MgcGHDrXNlcyBkZSBBbcOpcmljYSBkZWwgU3VyLCBzZWd1aWRvIHBvciBVcnVndWF5IHkgQXJnZW50aW5hLiBNaWVudHJhcyBxdWUsIEd1YXlhbmEgeSBCb2xpdmlhIHNvbiBsb3MgcGHDrXNlcyBjb24gbWVub3IgZXNwZXJhbnphIGRlIHZpZGEuDQoNCiMjIFBhcXVldGUgVE1BUA0KDQpTZSByZWFsaXphIHVuIG1hcGEgdXNhbmRvIGZ1bmNpb25lcyBkZWwgcGFxdWV0ZSB0bWFwLCBkb25kZSBzZSBjb21wYXJhbiBsb3MgdmFsb3JlcyBkZSBQQkkgcGVyIGPDoXBpdGEgZGUgbG9zIHBhw61zZXMgYWZyaWNhbm9zOg0KDQpgYGB7cn0NCnRtYXBfbW9kZSgicGxvdCIpDQphZnJpY2E9IHdvcmxkICU+JSBmaWx0ZXIoY29udGluZW50ID09ICJBZnJpY2EiKQ0KDQphZnJpY2EgJT4lIA0KICB0bV9zaGFwZSgpICsgDQogIHRtX2ZpbGwoaWQgPSAibmFtZV9sb25nIiwgY29sID0gImdkcFBlcmNhcCIpICsNCiAgdG1fc3R5bGUoImNvYmFsdCIpICsNCiAgdG1fYm9yZGVycygiYmxhY2siLCBsd2QgPSAxKSArIA0KICB0bV9taW5pbWFwKCkgKw0KICB0bV9iYXNlbWFwKCJTdGFtZW4uVG9uZXJCYWNrZ3JvdW5kIikrDQogIHRtX3RleHQoICJuYW1lX2xvbmciLCBzaXplPS42KQ0KYGBgDQoNCg0KDQpBIHBhcnRpciBkZSBlc3RlIG1hcGEgc2Ugb2JzZXJ2YSBxdWUgbG9zIHBhw61zZXMgY29uIG1heW9yIFBCSSBwZXIgY8OhcGl0YSBlbiDDgWZyaWNhIHNvbiBHdWluZWEgRWN1YXRvcmlhbCwgTGliaWEgeSBCb3Rzd2FuYS4gTWllbnRyYXMgcXVlIGxvcyBkZSBtZW5vciBQQkkgcGVyIGPDoXBpdGEgc29uLCBlbnRyZSBvdHJvczsgTmlnZXJpYSwgU3Vkw6FuLCBNYWRhZ2FzY2FyLCBldGMuIEhheSBtYXlvciBwcm9wb3JjacOzbiBkZSBwYcOtc2VzIGNvbiBQQkkgcGVyIGPDoXBpdGEgYmFqby4NCg0KDQoNCg0KDQoNCg==